/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package aliasMatching.cluster.timeBothA_B;

import aliasMatching.controller.TestFile;
import aliasMatching.controller.TimeClustering;
import aliasMatching.model.Alias;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * clustering the user according to their passive time. the users are divided
 * into 6 different cluster wrt time where they don't post anything in the
 * forum. After that the users clusters are created when they are mostly active
 * in discussion board.
 *
 * @author amendrashrestha
 */
public class ClusterUserNew {

    static List users = new ArrayList();
    static List postTime = new ArrayList();
    static List users0004 = new ArrayList();
    static List users0408 = new ArrayList();
    static List users0812 = new ArrayList();
    static List users1216 = new ArrayList();
    static List users1620 = new ArrayList();
    static List users2000 = new ArrayList();
    /* static List users0003 = new ArrayList();
     static List users0306 = new ArrayList();
     static List users0609 = new ArrayList();
     static List users0912 = new ArrayList();
     static List users1215 = new ArrayList();
     static List users1518 = new ArrayList();
     static List users1821 = new ArrayList();
     static List users2100 = new ArrayList();*/
    static List firstActivityPeak0004 = new ArrayList();
    static List firstActivityPeak0408 = new ArrayList();
    static List firstActivityPeak0812 = new ArrayList();
    static List firstActivityPeak1216 = new ArrayList();
    static List firstActivityPeak1620 = new ArrayList();
    static List firstActivityPeak2000 = new ArrayList();
    /* static List firstActivityPeak0003 = new ArrayList();
     static List firstActivityPeak0306 = new ArrayList();
     static List firstActivityPeak0609 = new ArrayList();
     static List firstActivityPeak0912 = new ArrayList();
     static List firstActivityPeak1215 = new ArrayList();
     static List firstActivityPeak1518 = new ArrayList();
     static List firstActivityPeak1821 = new ArrayList();
     static List firstActivityPeak2100 = new ArrayList();*/
    static HashMap<String, double[]> map = new HashMap<String, double[]>();
    static HashMap<List, List> activityPeakMap = new HashMap<List, List>();
    static HashMap<String, List> matchedUserMap;
    static HashMap<String, List> matrixMap = new HashMap<String, List>();
    static List firstUserPostTime, secondUserPostTime;
    static double[] timeStamp;
    static String firstUser, secondUser;
    private static List<String> userPostsTime;
    private static List<List> totalUserList;
    private static List<Alias> styloUser;
    private static List<String> matchedUser;
    private static List<List> firstPeakCluster;
    private static List<List> totalFirstActivityPeakCluster;

    public ClusterUserNew() {
    }

    public static void main(String args[]) {
        TestFile tf = new TestFile();
        TimeStyloClusterEqualityTest testCluster = new TimeStyloClusterEqualityTest();

        try {
            users = tf.getAllUsers();

//            users.add(3033);
//            users.add(3289);
//            users.add(5856);
//            users.add(1172);
//            users.add(5856);
//            users.add(7371);
//            users.add(17721);

//            users.add(2300);
//            users.add(7349);
//            users.add(9046);
//            users.add(111);
//            users.add(11022);
//            users.add(5355);
//            users.add(1538);
//            users.add(2288);
//            users.add(4147);
//            users.add(3112);
//            users.add(3033);
//            users.add(4210);
//            users.add(216);
//            users.add(732);
//            users.add(20040);
//            users.add(17587);
//            users.add(3179);
//            users.add(454);
//            users.add(2431);
//            users.add(16871);
            //int randomUser = getRandomUser(users); [1172_A, 5856_A

            divideTime(users);

            System.out.println("Total Users: " + users.size());
            System.out.println("Total User after Division: " + styloUser.size());

            //List tempList = returnMaxCluster(totalUserList);
            //int listSize = totalUserList.size();

            totalUserList = new ArrayList();
            totalUserList.add(users0004);
            totalUserList.add(users0408);
            totalUserList.add(users0812);
            totalUserList.add(users1216);
            totalUserList.add(users1620);
            totalUserList.add(users2000);

            /*totalUserList.add(users0003);
             totalUserList.add(users0306);
             totalUserList.add(users0609);
             totalUserList.add(users0912);
             totalUserList.add(users1215);
             totalUserList.add(users1518);
             totalUserList.add(users1821);
             totalUserList.add(users2100);*/

            int userSize = users.size();

            System.out.println("");
//            System.out.println("Size of Cluster: " + activityPeakMap.size());
//            System.out.println("First Activity Cluster");
//            System.out.println(activityPeakMap);


            firstPeakCluster = new ArrayList();

            for (List value : activityPeakMap.keySet()) {
                firstPeakCluster.add(activityPeakMap.get(value));
            }

            // clustering according to the peak number of post and within 
            //threshold of 0.1
            System.out.println("Cluster before 1st Activity Clustering");
            for (Map.Entry<List, List> peakMapEntry : activityPeakMap.entrySet()) {
                System.out.println(peakMapEntry);
            }

            firstActivityCluster(activityPeakMap);

            totalFirstActivityPeakCluster = new ArrayList();
            totalFirstActivityPeakCluster.add(firstActivityPeak0004);
            totalFirstActivityPeakCluster.add(firstActivityPeak0408);
            totalFirstActivityPeakCluster.add(firstActivityPeak0812);
            totalFirstActivityPeakCluster.add(firstActivityPeak1216);
            totalFirstActivityPeakCluster.add(firstActivityPeak1620);
            totalFirstActivityPeakCluster.add(firstActivityPeak2000);
            /*totalFirstActivityPeakCluster.add(firstActivityPeak0003);
             totalFirstActivityPeakCluster.add(firstActivityPeak0306);
             totalFirstActivityPeakCluster.add(firstActivityPeak0609);
             totalFirstActivityPeakCluster.add(firstActivityPeak0912);
             totalFirstActivityPeakCluster.add(firstActivityPeak1215);
             totalFirstActivityPeakCluster.add(firstActivityPeak1518);
             totalFirstActivityPeakCluster.add(firstActivityPeak1821);
             totalFirstActivityPeakCluster.add(firstActivityPeak2100);*/

            int firstActivityUserSize = 0;
            for (List<Object> sublist : totalFirstActivityPeakCluster) {
                firstActivityUserSize += sublist.size();
            }

            System.out.println("\nSleeping user List");
            /* System.out.println("00-04: " + users0004 + "\n");
             System.out.println("04-08: " + users0408 + "\n");
             System.out.println("08-12: " + users0812 + "\n");
             System.out.println("12-16: " + users1216 + "\n");
             System.out.println("16-20: " + users1620 + "\n");
             System.out.println("20-00: " + users2000);*/
            /*System.out.println("00-04: " + users0003 + "\n");
             System.out.println("04-08: " + users0306 + "\n");
             System.out.println("08-12: " + users0609 + "\n");
             System.out.println("12-16: " + users0912 + "\n");
             System.out.println("16-20: " + users1215 + "\n");
             System.out.println("20-00: " + users1518 + "\n");
             System.out.println("20-00: " + users1821 + "\n");
             System.out.println("20-00: " + users2100);*/

            System.out.println("\nActivity user List");
            System.out.println("Number of users in first Activity Cluster : " + firstActivityUserSize + "\n");
            /*System.out.println("00-04: " + firstActivityPeak0004 + "\n");
             System.out.println("04-08: " + firstActivityPeak0408 + "\n");
             System.out.println("08-12: " + firstActivityPeak0812 + "\n");
             System.out.println("12-16: " + firstActivityPeak1216 + "\n");
             System.out.println("16-20: " + firstActivityPeak1620 + "\n");
             System.out.println("20-00: " + firstActivityPeak2000 + "\n");*/

            /*System.out.println("00-04: " + firstActivityPeak0003 + "\n");
             System.out.println("04-08: " + firstActivityPeak0306 + "\n");
             System.out.println("08-12: " + firstActivityPeak0609 + "\n");
             System.out.println("12-16: " + firstActivityPeak0912 + "\n");
             System.out.println("16-20: " + firstActivityPeak1215 + "\n");
             System.out.println("20-00: " + firstActivityPeak1518 + "\n");
             System.out.println("20-00: " + firstActivityPeak1821 + "\n");
             System.out.println("20-00: " + firstActivityPeak2100 + "\n");*/



            //firstActivityPeak(totalUserList, map);
            //secondActivityPeak(totalUserList, map);
            //calculateMatchedPercentage(totalFirstActivityPeakCluster, userSize);

            HashMap<String, List> totalSleepingMap = calculateMatchedList(totalUserList, userSize);
            HashMap<String, List> totalActivityMap = calculateMatchedList(totalFirstActivityPeakCluster, userSize);



            System.out.println("TotalSleepingMap: " + totalSleepingMap);
            System.out.println("--------");
            //System.out.println("MatchedUser: " + matchedUser);
            System.out.println("TotalActivityMap: " + totalActivityMap);

            // double counter = 0.000;

            for (Map.Entry<String, List> sleepEntry : totalSleepingMap.entrySet()) {
                String SleepingCluster = sleepEntry.getKey();
                List SleepingUsers = sleepEntry.getValue();

                for (Map.Entry<String, List> activeEntry : totalActivityMap.entrySet()) {
                    List tempList = new ArrayList();
                    if (sleepEntry != null && activeEntry != null) {
                        String ActiveCluster = activeEntry.getKey();
                        List ActiveUsers = activeEntry.getValue();

                        //System.out.println("Sleeping Cluster: " + SleepingCluster);
                        //System.out.println("Sleeping Users: " + SleepingUsers);

                        for (int i = 0; i < SleepingUsers.size(); i++) {
                            if (tempList.size() != ActiveUsers.size()) {
                                if (ActiveUsers.contains(SleepingUsers.get(i))) {
                                    Integer tempUser = Integer.parseInt(SleepingUsers.get(i).toString());
                                    tempList.add(tempUser);
                                    matrixMap.put(SleepingCluster.concat(ActiveCluster), tempList);
                                    //counter++;
                                }
                                // }

                            } else {
                                break;
                            }
                        }
                    }
                }
            }
            System.out.println("\nActivity Cluster: ");
            for (Map.Entry<String, List> MatrixEntry : matrixMap.entrySet()) {
                System.out.println(MatrixEntry);
            }

            testCluster.calculateTimeStyloEquality(matrixMap);

            /**
             * Finding the matched user percentage
             */
            HashSet hs = new HashSet();
            for (Map.Entry<String, List> MatrixEntry : matrixMap.entrySet()) {
                List values = MatrixEntry.getValue();
                hs.addAll(values);
                values.clear();
                values.addAll(hs);
                //System.out.println(MatrixEntry);
            }

            double matchedUsersSize = (double) hs.size();
            System.out.println("\nMatched User Size: " + matchedUsersSize);
            System.out.println("\nMost Matched Percentage: " + (matchedUsersSize * 100) / userSize);



            // System.out.println("Matched Users: " + matchedUser);
        } catch (SQLException ex) {
        }
    }

    /**
     * return one random user from bulk of users
     *
     * @param users
     * @return
     */
    private static int getRandomUser(List users) {
        int user;

        Collections.shuffle(users);
        user = Integer.parseInt(users.get(0).toString());
        return user;
    }

    /**
     * calculates the number of users where UserX_A and UserX_B go to the same
     * cluster
     *
     * @param ActivityPeakUsers
     * @param clusterSize
     */
    private static HashMap calculateMatchedList(List<List> ActivityPeakUsers, int clusterSize) {
        List userA = new ArrayList();
        List userB = new ArrayList();

        matchedUserMap = new HashMap<String, List>();
        List tempUser;
        for (int a = 0; a < ActivityPeakUsers.size(); a++) {
            List bUsers = ActivityPeakUsers.get(a);
            tempUser = new ArrayList();
            matchedUser = new ArrayList<String>();
            for (int b = 0; b < bUsers.size(); b++) {
                String tempUsers = bUsers.get(b).toString();
                int userLengthSize = tempUsers.length();
                int indexOf_ = tempUsers.indexOf("_");
                String userType = tempUsers.substring(indexOf_, userLengthSize);
                String realUser = tempUsers.substring(0, indexOf_);
                if (userType.equals("_A")) {
                    userA.add(realUser);
                } else {
                    userB.add(realUser);
                }
            } // end for

            for (int i = 0; i < userA.size(); i++) {
                //System.out.println("Matched User List: " + matchedUser);
                //System.out.println("UserA : " + userA.get(i));

                if (matchedUser.contains(userA.get(i))) {
                    continue;
                } else if (userB.contains(userA.get(i))) {
                    //System.out.println("\nUserMatched: " + userA.get(i));
                    //System.out.println("Cluster A: " + (a + 1));
                    String tempUserA = userA.get(i).toString();
                    tempUser.add(tempUserA);
                    matchedUserMap.put(String.valueOf(a + 1), tempUser);
                    matchedUser.add(tempUserA);
                }
            }
            userA.clear();
            userB.clear();

            /*int matchedUserNumber = matchedUser.size();
             double matchedPercentage = (matchedUserNumber * 100) / clusterSize;
             System.out.println("\nMatched User Number: " + matchedUserNumber);
             System.out.println("Matched Percentage : " + matchedPercentage);*/

        }
        return matchedUserMap;
    }

    /**
     * the UserX is divided into UserX_A and UserX_B and respectively the post
     * time of UserX is also divided between UserX_A and UserX_B.
     *
     * @param user
     * @throws SQLException
     */
    public static void divideTime(List user) throws SQLException {

        styloUser = new ArrayList();
        // List users = new ArrayList();
        // users.add(user);

        TimeClustering se = new TimeClustering(user);
        styloUser = se.aliases;
        int userSize = styloUser.size();
        Alias[] tempAlias_A = new Alias[userSize];
        Alias[] tempAlias_B = new Alias[userSize];
        List activityPeakA = new ArrayList();
        List activityPeakB = new ArrayList();

        String[] tempUser = new String[userSize * 2];

        for (int i = 0; i < userSize; i++) {
            tempUser[i] = styloUser.get(0).getUser();
            divideUser(tempUser[i]);

            //for first user
            tempAlias_A[i] = new Alias(firstUser);
            tempAlias_A[i].setPostTime(firstUserPostTime);

            double[] tempTimeVectorA = tempAlias_A[i].getTimeVectorArray(firstUserPostTime);
            double[] normalizedVectorA = returnNormalizedTimeVector(tempTimeVectorA);

            //return normalized time vector
            tempAlias_A[i].setTimeStamp(normalizedVectorA);

            //finding peak hour for userA
            int peakHourIndexA = peakHourIndex(normalizedVectorA);
            activityPeakA = activityPeak(peakHourIndexA, normalizedVectorA);
            activityPeakCluster(firstUser, activityPeakA);

            styloUser.add(tempAlias_A[i]);

            inactivityCluster(normalizedVectorA, firstUser);
            map.put(firstUser, normalizedVectorA);

            //for second user
            tempAlias_B[i] = new Alias(secondUser);
            tempAlias_B[i].setPostTime(secondUserPostTime);

            double[] tempTimeVectorB = tempAlias_B[i].getTimeVectorArray(secondUserPostTime);
            double[] normalizedVectorB = returnNormalizedTimeVector(tempTimeVectorB);

            tempAlias_B[i].setTimeStamp(normalizedVectorB);
            int peakHourIndexB = peakHourIndex(normalizedVectorB);
            //System.out.println("Peak Hour Index for A: " + peakHourIndexB);
            activityPeakB = activityPeak(peakHourIndexB, normalizedVectorB);
            activityPeakCluster(secondUser, activityPeakB);

            styloUser.add(tempAlias_B[i]);

            inactivityCluster(normalizedVectorB, secondUser);
            map.put(secondUser, normalizedVectorB);

            styloUser.remove(0);
        }
    }

    /**
     * creating clusters of users having same activity peak time cluster
     *
     * @param user
     * @param activityPeak
     */
    public static void activityPeakCluster(String user, List activityPeak) {
        List userList = new ArrayList();

        userList.add(user);
        if (activityPeakMap.containsKey(activityPeak)) {
            List temp = activityPeakMap.get(activityPeak);
            temp.add(user);
            activityPeakMap.put(activityPeak, temp);
        } else {
            activityPeakMap.put(activityPeak, userList);
        }
    }

    /**
     * return normalized time vector with respect to total number of post
     *
     * @param timeVector
     * @return
     */
    public static double[] returnNormalizedTimeVector(double[] timeVector) {
        double sumB = 0;

        for (int index = 0; index < timeVector.length; index++) {
            sumB = sumB + timeVector[index];
        }

        for (int index = 0; index < timeVector.length; index++) {
            timeVector[index] = timeVector[index] / sumB;
        }
        return timeVector;
    }

    /**
     * returns index of maximum number of posts done
     *
     * @param hour
     * @return
     */
    public static int peakHourIndex(double[] hour) {
        int maxHourIndex = 0;
        double maxHour = 0.0;
        for (int i = 0; i < hour.length; i++) {
            if (hour[i] > maxHour) {
                maxHour = hour[i];
                maxHourIndex = i;
            }
        }
        return maxHourIndex;
    }

    /**
     * makes a cluster wrt to maximum index hour
     *
     * @param peakHourIndex
     * @param normalizedVector
     * @return
     */
    public static List activityPeak(int peakHourIndex, double[] normalizedVector) {
        List activityPeak = new ArrayList();
        activityPeak.add(peakHourIndex);
        double thresholdPercent = (60 * normalizedVector[peakHourIndex]) / 100;

        for (int x = peakHourIndex + 1; x < normalizedVector.length; x++) {
            if (normalizedVector[x] >= thresholdPercent) {
                activityPeak.add(x);
            } else {
                break;
            }
        }
        for (int y = peakHourIndex - 1; y >= 0; y--) {
            if (normalizedVector[y] >= thresholdPercent) {
                activityPeak.add(0, y);
            } else {
                break;
            }
        }

        /*for (int x = peakHourIndex + 1; x < normalizedVector.length; x++) {
         if (normalizedVector[x] - normalizedVector[peakHourIndex] <= 0.1) {
         activityPeak.add(x);
         } else {
         break;
         }
         }
         for (int y = peakHourIndex - 1; y >= 0; y--) {
         if (normalizedVector[y] - normalizedVector[peakHourIndex] <= 0.1) {
         activityPeak.add(0, y);
         } else {
         break;
         }
         }*/

        return activityPeak;
    }

    /**
     * creating cluster according to their inactivity in discussion board
     *
     * @param time
     * @param user
     */
    public static void inactivityCluster(double[] time, String user) {

        double[] post_count = time;
        // System.out.println("User: " + user);
        if (post_count[0] + post_count[1] + post_count[2] + post_count[3] == 0) {
            users0004.add(user);
        }
        if (post_count[4] + post_count[5] + post_count[6] + post_count[7] == 0) {
            users0408.add(user);
        }
        if (post_count[8] + post_count[9] + post_count[10] + post_count[11] == 0) {
            users0812.add(user);
        }
        if (post_count[12] + post_count[13] + post_count[14] + post_count[15] == 0) {
            users1216.add(user);
        }
        if (post_count[16] + post_count[17] + post_count[18] + post_count[19] == 0) {
            users1620.add(user);
        }
        if (post_count[20] + post_count[21] + post_count[22] + post_count[23] == 0) {
            users2000.add(user);
        }
        /*if (post_count[0] + post_count[1] + post_count[2] == 0) {
         users0003.add(user);
         }
         if (post_count[3] + post_count[4] + post_count[5] == 0) {
         users0306.add(user);
         }
         if (post_count[6] + post_count[7] + post_count[8] == 0) {
         users0609.add(user);
         }
         if (post_count[9] + post_count[10] + post_count[11] == 0) {
         users0912.add(user);
         }
         if (post_count[12] + post_count[13] + post_count[14] == 0) {
         users1215.add(user);
         }
         if (post_count[15] + post_count[16] + post_count[17] == 0) {
         users1518.add(user);
         }
         if (post_count[18] + post_count[19] + post_count[20] == 0) {
         users1821.add(user);
         }
         if (post_count[21] + post_count[22] + post_count[23] == 0) {
         users2100.add(user);
         }*/
    }

    /**
     * dividing single user into two user
     *
     * @param ID
     * @throws SQLException
     */
    public static void divideUser(String ID) throws SQLException {
        dividePostTime(ID);
        firstUser = ID + "_A";
        secondUser = ID + "_B";
    }

    /**
     * Splitting posts between users
     *
     * @param args
     * @throws SQLException
     */
    public static void dividePostTime(String ID) throws SQLException {
        userPostsTime = Alias.getAllPostTime(Integer.parseInt(ID));
        firstUserPostTime = new ArrayList();
        secondUserPostTime = new ArrayList();

        for (int i = 0; i < userPostsTime.size(); i++) {
            /**
             * The odd number post are assigned to first split user and even
             * number are assigned to second split user.
             */
            if (i % 2 == 0) {
                firstUserPostTime.add(userPostsTime.get(i));
            } else {
                secondUserPostTime.add(userPostsTime.get(i));
            }
        }
    }

    /**
     * returns the list having maximum numbers of users from the list of lists
     *
     * @param clusters
     * @return
     */
    public static List returnMaxCluster(List<List> clusters) {

        Iterator<List> itr = clusters.iterator();
        int max = -1;
        int index = -1;
        int counter = 0;

        while (itr.hasNext()) {
            List secondList = itr.next();
            if (secondList.size() > max) {
                max = secondList.size();
                index = counter;
            }
            counter++;
        }

        return clusters.get(index);
    }

    public static void firstActivityCluster(HashMap<List, List> activityPeakMap) {

        for (Map.Entry<List, List> entry : activityPeakMap.entrySet()) {
            List key = entry.getKey();
            List value = entry.getValue();
            int offset = 4;

            int checkSet04 = 0;
            int checkSet08 = 0;
            int checkSet12 = 0;
            int checkSet16 = 0;
            int checkSet20 = 0;
            int checkSet00 = 0;

            for (int i = 0; i < key.size(); i++) {
                int tempHour = Integer.parseInt(key.get(i).toString());
                int bucket = tempHour / offset;
                switch (bucket) {
                    case (0):
                        checkSet04 = 1;
                        break;
                    case (1):
                        checkSet08 = 1;
                        break;
                    case (2):
                        checkSet12 = 1;
                        break;
                    case (3):
                        checkSet16 = 1;
                        break;
                    case (4):
                        checkSet20 = 1;
                        break;
                    case (5):
                        checkSet00 = 1;
                        break;
                }
            }
            if (checkSet04 == 1) {
                firstActivityPeak0004.addAll(value);
            }
            if (checkSet08 == 1) {
                firstActivityPeak0408.addAll(value);
            }
            if (checkSet12 == 1) {
                firstActivityPeak0812.addAll(value);
            }
            if (checkSet16 == 1) {
                firstActivityPeak1216.addAll(value);
            }
            if (checkSet20 == 1) {
                firstActivityPeak1620.addAll(value);
            }
            if (checkSet00 == 1) {
                firstActivityPeak2000.addAll(value);
            }
        }
    }
}
